package com.king.hessian;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;

import org.apache.commons.io.IOUtils;
import org.slf4j.MDC;

import com.caucho.hessian.io.SerializerFactory;
import com.caucho.hessian.server.HessianSkeleton;

import lombok.extern.slf4j.Slf4j;

/**
 * 处理hessian请求的实现，大部分代码拷贝自hessian提供的HessianServlet。并加入MDC的部分用以把Http头X-Rpc-Client的数据放入log4j的上下文
 */
@Slf4j
public class HessianRpcServerImpl implements RpcServer {

    private final HessianSkeleton hessianSkeleton;

    private final SerializerFactory serializerFactory;

    public HessianRpcServerImpl(HessianSkeleton hessianSkeleton, SerializerFactory serializerFactory) {
        this.hessianSkeleton = hessianSkeleton;
        this.serializerFactory = serializerFactory;
    }

    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        HttpServletRequest req = request;
        HttpServletResponse res = response;
        String client = req.getHeader(RpcClientInfo.HTTP_HEADER_X_RPC_CLIENT);
        if (client == null) {
            client = RpcClientInfo.DEFAULT_CLIENT;
        }
        MDC.put("client", client);
        RpcClientInfo.setCurrentClient(client);

        try {
            if (!req.getMethod().equals("POST")) {
                res.sendError(405, "Method Not Allowed");
                res.addHeader("Allow", "POST");
                res.setContentType("text/html");
                PrintWriter out = res.getWriter();
                out.println("<h1>Hessian Requires POST</h1>");
                IOUtils.closeQuietly(out);
                return;
            }
            InputStream in = request.getInputStream();
            OutputStream out = response.getOutputStream();
            try {
                hessianSkeleton.invoke(in, out, serializerFactory);
            } catch (RuntimeException e) {
                log.error("hessian rpc 处理异常");
                throw new ServletException(e);
            } catch (Throwable e) {
                log.error("hessian rpc 处理异常");
                throw new ServletException(e);
            } finally {
                IOUtils.closeQuietly(in);
                IOUtils.closeQuietly(out);
            }
        } finally {
            RpcClientInfo.removeCurrentClient();
            MDC.remove("client");
        }
    }

}
